<template>
	<div class="uploader_wrapper">
		<div class="buttons">
			<div class="button" ref="uploadBtn">
				<slot name="button">
					<span class="sbtn">{{ !autoUpload ? '选择文件' : '上传文件' }}</span>
				</slot>
			</div>
			<div class="upload" v-if="!autoUpload" @click="handleUploadFile">
				<slot name="upload">
					<span class="ubtn">上传文件</span>
				</slot>
			</div>
			<div class="tips">
				<slot name="tips"></slot>
			</div>
		</div>
		<div class="lists">
			<template v-if="echoFileList.length > 0">
				<echo-item v-for="file in echoFileList" :key="file.id" :current-checked="selectedFile" :file="file" :is-check="isCheck"
					v-on="$listeners"></echo-item>
			</template>
			<template v-if="uploadList.length > 0">
				<file-item v-for="file in uploadList" :key="file.id" :file="file" :is-check="isCheck" v-on="$listeners"></file-item>
			</template>
		</div>
	</div>
</template>

<script>
import fileItem from './fileItem';
import echoItem from './echoItem';
import { mapGetters } from 'vuex';
import { Message } from 'element-ui';
import Uploader from 'simple-uploader.js';
import { chunkSize, baseParams, checkUpload, chunkUpload } from './config';
export default {
	name: 'swSimpleUploader',
	components: { fileItem, echoItem },
	props: {
		value: String,
		autoUpload: {
			type: Boolean,
			default: true
		},
		attachType: {
			type: String,
			default: '1'
		},
		attachList: {
			type: Array,
			default () {
				return [];
			}
		},
		resType: {
			type: String,
			default: '1'
		},
		isCheck: {
			type: Boolean,
			default: false
		},
		accept: String,
		fileLimitSize: [String, Number],
		getUploadNum: Function
	},
	provide() {
		return {
			autoUpload: this.autoUpload
		};
	},
	data() {
		return {
			selectedFile: '',
			uploader: null,
			uploadList: [],
			checkResponse: [],
			uploadFiles: []
		};
	},
	computed: {
		...mapGetters(['token']),
		echoFileList() {
			return this.attachList;
		},
		fileList() {
			return [...this.echoFileList, ...this.uploadFiles];
		},
		busiAttachSize() {
			return Number(this.fileLimitSize) || 50 * 1024 * 1024 * 1024;
		},
		uploadFileNum() {
			return this.uploadList.length + this.echoFileList.length;
		}
	},
	mounted() {
		this.createUploaderInstance();
	},
	watch: {
		uploader(instance) {
			this.initUploader(instance);
		},
		value(val) {
			this.selectedFile = val;
		},
		selectedFile(val) {
			this.$emit('input', val);
			this.$parent.$emit('el.form.change');
		},
		uploadList: {
			handler(data) {
				let arr = [];
				data.forEach(file => {
					let fileInfo = this.checkResponse.find(item => file.md5Value === item.md5Value);
					if(!!fileInfo) {
						fileInfo['checked'] = !file.checked ? false : true;
						arr.push(fileInfo);
					}
				});
				this.uploadFiles = [...arr];
			},
			deep: true
		},
		fileList(data) {
			this.$nextTick(() => {
				this.selectedFile = data.map(item => item.id).join();
				this.$emit('change', data);
			});
		},
		uploadFileNum: {
			handler(nval, oval) {
				if(nval !== oval && !!this.getUploadNum) {
					this.getUploadNum(nval);
				}
			},
			immediate: true
		}
	},
	methods: {
		createUploaderInstance() {
			this.uploader = new Uploader({
				target: (file, chunk, check) => {
					if(check) {
						return checkUpload;
					} else {
						return chunkUpload;
					}
				},
				singleFile: false,
				testChunks: true, //是否开启服务器分片校验
				chunkSize: chunkSize, //分块大小
				fileParameterName: 'file', //上传文件时文件的参数名，默认file
				maxChunkRetries: 3, //最大自动失败重试上传次数
				simultaneousUploads: 1,
				testMethod: 'POST',
				initialPaused: true,
				processParams: (params, file, chunk, check) => {
					let obj = {};
					if(check) {
						obj = {
							...baseParams,
							type: this.attachType,
							attrSize: params.totalSize,
							oldName: params.filename,
							diskType: this.resType
						};
					} else {
						let checkInfo = this.checkResponse.find(item => item.md5Value === file.md5Value);
						obj = { chunk: params.chunkNumber - 1, newName: checkInfo.newName };
					}
					obj['md5Value'] = file.md5Value;
					return obj;
				},
				checkChunkUploadedByResponse: (chunk, message) => {
					let msgInfo = JSON.parse(message);
					if(msgInfo.code === 0) {
						let datas = msgInfo.data[0];
						let fileInfo = this.uploadList.find(item => item.md5Value === datas.md5Value);
						let checkInfo = this.checkResponse.find(item => item.md5Value === datas.md5Value);
						if(!checkInfo) {
							fileInfo['fileId'] = datas.id;
							this.checkResponse.push(datas);
						} else if(!fileInfo.fileId) {
							fileInfo['fileId'] = checkInfo.id;
						}
						if(datas.isFinish === '1') {
							return true;
						} else {
							return false;
						}
					} else {
						return true;
					}
				},
				headers: { Authorization: this.token }
			});
		},
		initUploader(uploader) {
			uploader.assignBrowse(this.$refs.uploadBtn, false, false, {
				accept: this.accept
			});
			uploader.on('fileAdded', (file, event) => {
				if(!!this.accept) {
					let busiAttachType = !this.accept ? [] : this.accept.split(',');
					if(busiAttachType.indexOf('.' + file.getExtension()) === -1) {
						Message({
							type: 'warning',
							message: `您选择的 <font color="#f00"><strong>${file.getExtension()}</strong></font> 文件不在系统设定可上传文件类型范围内，请联系管理员添加此类型文件为可上传类型`,
							offset: 80,
							duration: 8000,
							showClose: true,
							dangerouslyUseHTMLString: true
						});
						return false;
					}
				}
				if(file.size > this.busiAttachSize * 1024 * 1024) {
					Message({
						type: 'warning',
						message: `您选择的文件大小超过系统预设值 <font color="#f00"><strong>${
							this.busiAttachSize
						}MB</strong></font>，请联系管理员修改系统预设值或重新上传较小的文件`,
						offset: 80,
						duration: 8000,
						showClose: true,
						dangerouslyUseHTMLString: true
					});
					return false;
				}
				this.$nextTick(() => {
					this.uploadList = uploader.files;
				});
			});
			uploader.on('fileRemoved', file => {
				let index = this.checkResponse.findIndex(item => item.md5Value === file.md5Value);
				this.checkResponse.splice(index, 1);
			});
			uploader.on('fileSuccess', async (rootFile, file, message) => {
				let msgInfo = JSON.parse(message);
				if(msgInfo.code === 0) {
					let datas = msgInfo.data[0];
					if(datas.isFinish === '1') {
						file['success'] = true;
					} else {
						file['merging'] = true;
					}
				}
			});
			uploader.on('fileComplete', rootFile => {});
			uploader.on('fileError', (rootFile, file, message) => {});
			uploader.on('fileProgress', (rootFile, file, chunk) => {});
			uploader.on('complete', () => {
				this.$emit('finish');
			});
		},
		handleUploadFile() {
			this.uploader.resume();
		}
	}
};
</script>

<style scoped>
.uploader_wrapper {}

.uploader_wrapper .buttons {
	display: flex;
}

.uploader_wrapper .button {
	margin-right: 10px;
	cursor: pointer;
}

.uploader_wrapper span.sbtn,
.uploader_wrapper span.ubtn {
	display: flex;
	align-items: center;
	height: 100%;
	font-size: 14px;
	line-height: inherit;
	padding: 0 15px;
	border: none 0;
	color: #fff;
	border-radius: 4px;
	user-select: none;
	transition: background-color 0.1s linear;
}

.uploader_wrapper .button span.sbtn {
	background-color: var(--primary);
}

.uploader_wrapper .button span.sbtn:hover {
	background-color: var(--primary-hover);
}

.uploader_wrapper .upload {
	margin-right: 10px;
	cursor: pointer;
}

.uploader_wrapper .upload span.ubtn {
	background-color: #67c23a;
}

.uploader_wrapper .upload span.ubtn:hover {
	background-color: rgba(103, 194, 58, 0.75);
}

.uploader_wrapper .tips {
	color: #999;
}

.uploader_wrapper .lists {
	margin-top: 10px;
}
</style>